/*
 * Copyright (C) 2006  Antonie Struyk
 *
 * This file is part of MusicFlashCards.
 *
 *    Freetar Hero is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    MusicFlashCards is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MusicFlashCards; if not, write to the Free Software
 *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package com.antonstruyk.musicflashcards;

import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.List;
import java.util.ArrayList;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.net.URL;
import java.io.IOException;
import javax.swing.JOptionPane;
import java.awt.Image;
import javax.swing.ImageIcon;

/**
 *
 * @author Anton
 */
public class NoteDisplayPanel extends JPanel{
    private static final int TOTAL_NOTES = 32;

    private static final int NOTE_HEIGHT = 12;
    private static final int NOTE_WIDTH = 20;
    private static final int BUFFER = NOTE_WIDTH;
    
    private List<Note> notesToDraw;
    private Image trebleCleffImage;
    private Image bassCleffImage;
    private boolean drawNoteNames;
    
    /** Creates a new instance of NoteDisplayPanel */
    public NoteDisplayPanel() {
        //Some graphics stuff
        this.setBackground(Color.WHITE);
        
        //Initialize the variables
        notesToDraw = new ArrayList<Note>();
        
        //Load the images
        URL cleffURL = this.getClass().getClassLoader().getResource("trebleCleff.png");
        URL bassURL = this.getClass().getClassLoader().getResource("bassCleff.png");
        try{
            trebleCleffImage = new ImageIcon(cleffURL).getImage();
        }catch(NullPointerException e){
            System.err.println("Could not find the image for the Treble Cleff");
        }
        
        try{
            bassCleffImage = new ImageIcon(bassURL).getImage();
        }catch(NullPointerException e){
            System.err.println("Could not find the image for the Bass Cleff");
        }
        
        drawNoteNames = false;
    }
    
    public void addNote(Note n){
        if(!notesToDraw.contains(n) && n != null){
            notesToDraw.add(n);
            this.repaint();
        }
    }
    
    public void removeNote(Note n){
        notesToDraw.remove(n);
        this.repaint();
    }
    
    public void clearNotes(){
        notesToDraw.clear();
        this.repaint();
    }
    
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        
        drawStaffLines(g);
        drawTrebleCleff(g);
        drawBassCleff(g);
        
        for(Note n : notesToDraw){
            drawNote(n, g);
        }
    }
    
    public void drawTrebleCleff(Graphics g){
        if(trebleCleffImage == null) return;
        
        int yTopPosition = yPos(26) + lineHeight() / 2;      //Center of note 26
        int yBottomPosition = yPos(15) + lineHeight() / 2;   //Center of note 15
        int newHeight = Math.abs(yTopPosition - yBottomPosition);
        float scale = (float) newHeight / (float) trebleCleffImage.getHeight(null);
        int newWidth = (int) (trebleCleffImage.getWidth(null) * scale);
        
        g.drawImage(trebleCleffImage, BUFFER, yTopPosition, newWidth, newHeight, null);
    }
    
    public void drawBassCleff(Graphics g){
        if(bassCleffImage == null) return;
        
        int yTopPosition = yPos(12) + lineHeight() / 2;      //Center of note 12
        int yBottomPosition = yPos(5) + lineHeight() / 2;    //Center of note 5
        int newHeight = Math.abs(yTopPosition - yBottomPosition);
        float scale = (float) newHeight / (float) bassCleffImage.getHeight(null);
        int newWidth = (int) (bassCleffImage.getWidth(null) * scale);
        
        g.drawImage(bassCleffImage, BUFFER, yTopPosition, newWidth, newHeight, null);
    }
    
    public void drawStaffLines(Graphics g){
        //Bass Cleff Lines
        for(int i = 4; i <= 12; i+= 2){
            g.drawLine(BUFFER,
                    yPos(i) + lineHeight() / 2,
                    this.getWidth() - BUFFER,
                    yPos(i) + lineHeight() / 2);
        }
        
        //Treble Cleff Lines
        for(int i = 16; i <= 24; i+= 2){
            g.drawLine(BUFFER,
                    yPos(i) + lineHeight() / 2,
                    this.getWidth() - BUFFER,
                    yPos(i) + lineHeight() / 2);
        }
    }
    
    public void drawNote(Note n, Graphics g){
        //Find the y-position of the top of the note...
        int xPos = xPos(n.getNumber());
        int yPos = yPos(n.getNumber());
        
        /*
        g.setColor(Color.GRAY);
        g.drawRect(xPos, yPos, NOTE_SPACING, LINE_HEIGHT);
        g.drawLine(xPos + (NOTE_SPACING - NOTE_WIDTH) / 2 - NOTE_WIDTH / 2,
                yPos,
                xPos + NOTE_SPACING - (NOTE_SPACING - NOTE_WIDTH) / 2 + NOTE_WIDTH / 2,
                yPos + LINE_HEIGHT);
        */
        
        if(n.getNumber() % 2 == 0){
            //Draw the background line..
            g.setColor(Color.BLACK);
            g.drawLine(xPos + (noteSpacing() - NOTE_WIDTH) / 2 - NOTE_WIDTH / 2,
                    yPos + lineHeight() / 2,
                   xPos + noteSpacing() - (noteSpacing() - NOTE_WIDTH) / 2 + NOTE_WIDTH / 2,
                    yPos + lineHeight() / 2);
        }
        //Draw the circle representing the note
        g.setColor(Color.BLACK);
        g.fillOval(xPos + (noteSpacing() - NOTE_WIDTH) / 2,
                yPos + (lineHeight() - NOTE_HEIGHT) / 2,
                NOTE_WIDTH,
                NOTE_HEIGHT);
        
        
        if(drawNoteNames){
            g.setColor(Color.RED);
            Font oldFont = g.getFont();
            g.setFont(oldFont.deriveFont(Font.BOLD, 14));
            
            FontMetrics m = g.getFontMetrics();
            int width = m.stringWidth(n.getName());
            int height = m.getHeight();
            
            g.drawString(n.getName(), xPos + noteSpacing() / 2 - width / 2, yPos + m.getHeight() + 2);
            g.setFont(oldFont);
        }
    }
    
    public void showNoteNames(boolean showNames){
        drawNoteNames = showNames;
        this.repaint();
    }
    
    /**
     *Finds the y-position of the top-left position of the LINE the note should be placed on
     **/
    private int yPos(int noteIndex){
        return (lineHeight() * TOTAL_NOTES) - (lineHeight() * noteIndex) + BUFFER;
    }
    
    private int xPos(int noteIndex){
        return  noteIndex * noteSpacing() + BUFFER;
    }
    
    private int noteSpacing(){
        return (this.getWidth() - 2 * BUFFER) / TOTAL_NOTES;
    }
    
    private int lineHeight(){
        return (this.getHeight() - 2 * BUFFER) / TOTAL_NOTES;
    }
}
